Laboratorio 6: El Pandas no Muerde (act IV) 🐼

MDS7202: Laboratorio de Programación Científica para Ciencia de Datos

Cuerpo Docente:¶

  • Profesores: Pablo Badilla, Ignacio Meza
  • Auxiliar: Sebastián Tinoco
  • Ayudante: Felipe Arias, Diego Cortez

Equipo: SUPER IMPORTANTE - notebooks sin nombre no serán revisados¶

  • Nombre de alumno 1:
  • Nombre de alumno 2:

Link de repositorio de GitHub: http://....¶

Reglas:¶

  • Grupos de 2 personas
  • Asistencia obligatoria a instrucciones del lab (viernes 16.15). Luego, pueden quedarse trabajando en las salas o irse.
  • No se revisarán entregas de personas ausentes.
  • Cualquier duda fuera del horario de clases al foro. Mensajes al equipo docente serán respondidos por este medio.
  • Prohibidas las copias.
  • Pueden usar cualquer matrial del curso que estimen conveniente.

Objetivos principales del laboratorio¶

  • Aplicar los paradigmas y buenas prácticas de programación vistas hasta este momento.
  • Comprender y aprovechar las ventajas que nos ofrece la liberia numpy con respecto a trabajar en Python 'puro'.
  • Visualizar aplicaciones de filtros de imágenes sin el uso de librerías.
  • Verificar que el uso indiscriminado de for puede afectar en la eficiencia en al procesar datos masivos.

El laboratorio deberá ser desarrollado sin el uso indiscriminado de iteradores nativos de python (aka "for", "while"). La idea es que aprendan a exprimir al máximo las funciones optimizadas que nos entrega numpy, las cuales vale mencionar, son bastante más eficientes que los iteradores nativos sobre arreglos (o tensores).

Descripción del laboratorio.¶

Importamos librerias utiles 😸¶

In [1]:
# Libreria Core del lab.
import numpy as np
!pip install --upgrade pandas
!pip install xlrd
!pip install openpyxl
import pandas as pd
import datetime
from scipy import stats

from IPython.display import display, Markdown, Latex

#Libreria para plotear
!pip install --upgrade plotly
!pip install missingno
import matplotlib.pyplot as plt
import missingno as msno
import plotly.express as px
Requirement already satisfied: pandas in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (2.0.1)
Requirement already satisfied: pytz>=2020.1 in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from pandas) (2022.7)
Requirement already satisfied: numpy>=1.20.3 in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from pandas) (1.22.4)
Requirement already satisfied: python-dateutil>=2.8.2 in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from pandas) (2.8.2)
Requirement already satisfied: tzdata>=2022.1 in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from pandas) (2023.3)
Requirement already satisfied: six>=1.5 in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from python-dateutil>=2.8.2->pandas) (1.16.0)
Requirement already satisfied: xlrd in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (2.0.1)
Requirement already satisfied: openpyxl in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (3.0.10)
Requirement already satisfied: et_xmlfile in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from openpyxl) (1.1.0)
Requirement already satisfied: plotly in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (5.14.1)
Requirement already satisfied: packaging in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from plotly) (23.0)
Requirement already satisfied: tenacity>=6.2.0 in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from plotly) (8.0.1)
Requirement already satisfied: missingno in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (0.5.1)
Requirement already satisfied: numpy in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from missingno) (1.22.4)
Requirement already satisfied: scipy in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from missingno) (1.7.3)
Requirement already satisfied: seaborn in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from missingno) (0.12.2)
Requirement already satisfied: matplotlib in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from missingno) (3.6.3)
Requirement already satisfied: cycler>=0.10 in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from matplotlib->missingno) (0.11.0)
Requirement already satisfied: packaging>=20.0 in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from matplotlib->missingno) (23.0)
Requirement already satisfied: pillow>=6.2.0 in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from matplotlib->missingno) (9.4.0)
Requirement already satisfied: fonttools>=4.22.0 in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from matplotlib->missingno) (4.25.0)
Requirement already satisfied: python-dateutil>=2.7 in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from matplotlib->missingno) (2.8.2)
Requirement already satisfied: kiwisolver>=1.0.1 in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from matplotlib->missingno) (1.4.4)
Requirement already satisfied: pyparsing>=2.2.1 in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from matplotlib->missingno) (3.0.9)
Requirement already satisfied: contourpy>=1.0.1 in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from matplotlib->missingno) (1.0.5)
Requirement already satisfied: pandas>=0.25 in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from seaborn->missingno) (2.0.1)
Requirement already satisfied: pytz>=2020.1 in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from pandas>=0.25->seaborn->missingno) (2022.7)
Requirement already satisfied: tzdata>=2022.1 in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from pandas>=0.25->seaborn->missingno) (2023.3)
Requirement already satisfied: six>=1.5 in /Users/stino/opt/anaconda3/lib/python3.8/site-packages (from python-dateutil>=2.7->matplotlib->missingno) (1.16.0)
In [2]:
# Si usted está utilizando Colabolatory le puede ser útil este código para cargar los archivos.
try:
    from google.colab import drive
    drive.mount("/content/drive")
    path = 'Dirección donde tiene los archivos en el Drive'
except: 
    print('Ignorando conexión drive-colab')
Ignorando conexión drive-colab

Segmentación de Clientes en Tienda de Retail 🛍️¶

1.1 Cargar Dataset¶

Mr. Lepin Mora quien es el gerente de una cotizada tienda de retail en Europa, les solicita si pueden analizar los datos de algunas de sus tiendas.

Para esto, el área de ventas les entrega el archivo online_retail_II.pickle con el que se les pide que cargue y visualicen algunas de las filas que componen el Dataset.

Realice una primera visualización de los datos y señale los atributos que componen el dataset. Señale las columnas que conforman el dataset, el tipo de variable presente en cada columna y comente que representa cada una de estas.

Respuesta:

In [3]:
df_retail = pd.read_pickle("online_retail_II.pickle")
df_retail = df_retail.astype(
    {
        "Invoice": "category",
        "StockCode": "category",
        "Description": str,
        "Customer ID": "category",
    }
)
df_retail.head()
Out[3]:
Invoice StockCode Description Quantity InvoiceDate Price Customer ID Country
0 489434 85048 15CM CHRISTMAS GLASS BALL 20 LIGHTS 12 2009-12-01 07:45:00 6.95 13085.0 United Kingdom
1 489434 79323P PINK CHERRY LIGHTS 12 2009-12-01 07:45:00 6.75 13085.0 United Kingdom
2 489434 79323W WHITE CHERRY LIGHTS 12 2009-12-01 07:45:00 6.75 13085.0 United Kingdom
3 489434 22041 RECORD FRAME 7" SINGLE SIZE 48 2009-12-01 07:45:00 2.10 13085.0 United Kingdom
4 489434 21232 STRAWBERRY CERAMIC TRINKET BOX 24 2009-12-01 07:45:00 1.25 13085.0 United Kingdom

1.2 Analisís Explotatorio de los Datos [0.5 puntos]¶

En base a la primera visualización del dataset, Don Mora le solicita que realicen un análisis exploratorio de los datos, para esto les deberán realizar un análisis univariado y multivariado. De la revisión, ustedes deben explicar potenciales anomalías visualizadas y señalar si existe la necesidad de realizar una limpieza de datos.

Explique a que nos referimos con análisis univariable, multivariable y de datos faltantes. ¿Qué beneficios nos otorga estudiar estos datos?. Sea conciso con su respuesta y no escriba mas de 5 líneas para su respuesta.

Respuesta a la Pregunta:

Respuesta Aquí

1.2.1 Análisis Univariado [2 Puntos]¶

A continuación, se le presentan dos funciones para analizar los datos que componen un dataframe. La primera de estas es la función profile_serie() la cual recibe una serie y le entrega un análisis detallado de los datos que conforman dicha serie.

Ejecute la funcion profile_serie() sobre cada serie para realizar un análisis univariado de estas. A continuación, comente acerca de el comportamiento de cada variable según las estadísticas descriptivas y los gráficos generados.

In [4]:
from pandas.api.types import is_numeric_dtype
from pandas.core.dtypes.common import is_datetime_or_timedelta_dtype


def profile_serie(serie_in, n_samples=1000, random_state=42):
    serie = serie_in.copy()

    profile = pd.Series(dtype='object')
    profile["Type"] = serie.dtype
    profile = pd.concat([profile, serie.describe()])

    # profile = pd.Series([])

    if is_numeric_dtype(serie):
        profile["Negative"] = (serie < 0).sum()
        profile["Negative (%)"] = (
            str(round((serie < 0).sum() / len(serie) * 100, 2)) + " %"
        )
        profile["Zeros"] = (serie == 0).sum()
        profile["Zeros (%)"] = (
            str(round((serie == 0).sum() / len(serie) * 100, 2)) + " %"
        )
        profile["Kurt"] = serie.kurt()
        profile["Skew"] = serie.skew()

    profile[" "] = " "  # espacio

    profile["Missing cells"] = serie.isnull().sum()
    profile["Missing cells (%)"] = (
        str(round(serie.isnull().sum() / len(serie) * 100, 2)) + " %"
    )
    profile["Duplicate rows"] = serie.duplicated(False).sum()
    profile["Duplicate rows (%)"] = (
        str(round(serie.duplicated(False).sum() / len(serie) * 100, 2)) + " %"
    )
    profile["Total size in memory"] = str(serie.memory_usage(index=True)) + " bytes"

    # profile = pd.concat([profile, description])

    profile = profile.rename(
        index={
            "count": "Number of observations",
            "mean": "Mean",
            "std": "Std",
            "min": "Min",
            "max": "Max",
            "unique": "Unique",
            "top": "Top",
            "freq": "Freq",
        }
    )
    no_outliers_fig = None

    if is_numeric_dtype(serie):

        sampled_serie = serie.sample(n_samples, random_state=random_state)
        fig = px.histogram(
            sampled_serie, marginal="box", title=f"{serie.name} - With Outliers"
        )

        no_outliers = sampled_serie.loc[(np.abs(stats.zscore(sampled_serie)) < 3)]
        # zscore = https://es.wikipedia.org/wiki/Unidad_tipificada
        
        no_outliers_fig = px.histogram(
            no_outliers, marginal="box", title=f"{serie.name} - Without Outliers"
        )

    elif is_datetime_or_timedelta_dtype(serie):
        sampled_serie = serie.sample(n_samples, random_state=random_state)
        fig = px.histogram(sampled_serie, marginal="box", title=f"{serie.name}")
    
    else:
        count = (
            serie.value_counts()[0:100]
            .reset_index()
            .rename(columns = {'count': 'Count'})
        )
        fig = px.bar(
            x=count[serie.name].astype(str),
            y=count["Count"],
            title=f"100 Most common categories of {serie.name}",
        )
    display(Markdown(f'## {serie.name} Profile'))
    display(profile)
    fig.show()

    if no_outliers_fig:
        no_outliers_fig.show()

    # return fig, profile
In [5]:
profile_serie(df_retail['Price']) 

Price Profile¶

Type                            float64
Number of observations         525461.0
Mean                           4.688834
Std                          146.126914
Min                           -53594.36
25%                                1.25
50%                                 2.1
75%                                4.21
Max                            25111.09
Negative                              3
Negative (%)                      0.0 %
Zeros                              3687
Zeros (%)                         0.7 %
Kurt                       64868.344873
Skew                        -140.768446
                                       
Missing cells                         0
Missing cells (%)                 0.0 %
Duplicate rows                   524485
Duplicate rows (%)              99.81 %
Total size in memory      4203816 bytes
dtype: object
Análisis de la primera serie...
In [ ]:
profile_serie(...)
Análisis de la n-esima serie...

1.2.2 Análisis Multivariado y Datos Faltantes [1 ptos]¶

En segundo lugar encontrará la función profile_df() que recibe un dataframe como entrada y realiza un análisis bivariado de todas las variables numéricas que conforman el dataframe, un analisis de la correlación de Pearson entre las variables numericas del dataframe y la matriz de datos faltantes.

In [ ]:
def profile_df(dataframe_in):
    df = dataframe_in.copy()

    list_type = []
    for col in list(df.columns):
        if is_numeric_dtype(df[col]) or \
        pd.core.dtypes.common.is_datetime_or_timedelta_dtype(df[col]):
            list_type.append(col)

    
    display(Markdown('## Bivariant Analysis:'))
    for i in range(len(list_type)):
        for j in range(i+1, len(list_type)):
            plt.scatter(df[list_type[i]], df[list_type[j]])
            plt.xlabel(list_type[i]) 
            plt.ylabel(list_type[j]) 
            plt.title(f"{list_type[i]} v/s {list_type[j]}")
            plt.show()

    display(Markdown('## Correlation:'))
    fig_corr = px.imshow(df[list_type].corr())
    fig_corr.show()

    display(Markdown('## Missing Matrix:'))
    fig, ax = plt.subplots(figsize=[15, 10])
    msno.matrix(df, ax=ax, sparkline=False)

1.2.3 Limpieza de Datos [1 pto]¶

Como pudo ver en las secciones anteriores, los datos presentan valores erroneos, es por esto que se le solicita que realice una función que permita limpiar el dataset. Realice esta función en base observaciones propias y considere como imposible tener cantidades negativas en las ventas.

Una vez realizada la función, realice nuevamente el análisis exploratorio y comente las principales diferencias.

Respuesta:

In [ ]:
> Código Aquí

1.2.4 Obtención de TOPs [0.75 ptos]¶

Sin considerar los comentarios realizados en la sección 1.2 , Don Mora les pide obtener el Top de 30 productos que generan más ganancias para la tienda de retail. Deben considerar todo el registro temporal presente en el dataset y entregar la información en un gráfico de barras de los ingresos/cantidades v/s el nombre de los productos (Utilice plotly). ¿Los artículos más vendidos son los mismos que generan más ganancias?, Comente los resultados obtenidos.

Resultados:

In [ ]:
> Código Aquí

1.2.5 Visualización del registro temporal [0,75 ptos]¶

El dueño del retail en su afán por saber más sobre los datos de su firma les solicita que grafiquen las ventas respecto al tiempo. Con esto les aclara que durante el día tienen muchas variaciones en sus ventas, por lo que les recomienda que consideren el registro temporal como año-mes-día. ¿Es posible observar datos extraños?, Comente lo que observa del gráfico.

In [ ]:
def plot_ventas(dataframe):
    pass

Conclusión¶

Eso ha sido todo para el lab de hoy, recuerden que el laboratorio tiene un plazo de entrega de una semana. Cualquier duda del laboratorio, no duden en contactarnos por mail o U-cursos.

Gracias Totales!



Created in deepnote.com Created in Deepnote